package oop.core;

import java.util.Date;
import java.util.List;

import oop.core.view.GamePanel;
import oop.core.view.MainMenu;
import oop.core.view.SizeablePanel;

/**
 * Class to handle time and restrict frames per second.
 * @author DangMH
 */
public class GameLoop implements Runnable {
	private long milliSecondsPerFrame;	/* sleep time between frames */
	private long lastFrameTime;		/* marker for time before actions and sleep is called */
	private long currFrameTime;		/* marker for finding modified sleep time */
	private Scheduler scheduler;	/* Scheduler object for frame notifications */
	private boolean running;		/* boolean flag for current */
	
	private List<SizeablePanel> panels;
//	private GamePanel gamePanel;
	
	/**
	 * Empty constructor not supported, needs a game!
	 * @throws NoSuchMethodException 
	 */
	public GameLoop() throws NoSuchMethodException
	{
		throw new NoSuchMethodException("Needs to be passed a scheduler");
	}
	
	public GameLoop(Scheduler scheduler, List<SizeablePanel> panels)
	{
		this(60, scheduler);
		this.panels = panels;
//		this.gamePanel = gamePanel;
	}
	
	/**
	 * Parameterized constructor.
	 * secondsPerFrame is derived from 1/framesPerSecond.
	 * @param framesPerSecond
	 * @param scheduler
	 */
	public GameLoop(int framesPerSecond, Scheduler scheduler )
	{
		running = false;
		milliSecondsPerFrame = (long)( 1000 / (double)framesPerSecond );
		this.scheduler = scheduler;
	}
	
	/**
	 * Accessor for scheduler.
	 * @return
	 */
	public Scheduler getScheduler()
	{
		return scheduler;
	}
	
	/**
	 * Operation to run the GameLoop.
	 * Initializes running flag to true.
	 * Operation stops running when stopLoop() is called.
	 */
	public void run()
	{
		running = true;
		lastFrameTime = System.currentTimeMillis();

//		System.out.println("Game panel null? " + (gamePanel==null));
		while( running )
		{
			scheduler.update( System.currentTimeMillis() - lastFrameTime );
			
			lastFrameTime = System.currentTimeMillis();
			
//			gamePanel.repaint();
			for(SizeablePanel panel : panels)
			{
				panel.repaint();
			}
//			gamePanel.repaint();
			
			//System.out.println( toString() + "\ndiff = " + currFrameTime );
			
			currFrameTime = System.currentTimeMillis() - lastFrameTime;
			if( currFrameTime < milliSecondsPerFrame )
			{
				//System.out.println( "sleeping: " + (milliSecondsPerFrame - currFrameTime) );
				
				//System.out.println( "time before sleeping: " + System.currentTimeMillis() );
				
				try
				{
					Thread.sleep( milliSecondsPerFrame - currFrameTime );
				}
				catch( InterruptedException ie )
				{
					break;
				}
				
				//System.out.println( "time after sleeping: " + System.currentTimeMillis() );
			}
		}
		
		endGame();
	}
	
	public void endGame(){
		//RunGame.changePanel(DeathScreen.ID);
		System.exit(1337);
	}
	
	
	/**
	 * Operation to stop GameLoop from running.
	 */
	public void stopLoop()
	{
		running = false;
	}
	
	/**
	 * toString method to access time status.
	 * @return
	 */
	public String toString()
	{
		return "FPS = " + ( 1000 / milliSecondsPerFrame ) +"\n" +
				"Last Frame Occured = " + lastFrameTime + "\n" +
				"Current Time = " + System.currentTimeMillis();
	}
}
